//事件 的 回调（回调函数和目标对象）
var callFuncs = cc.Class({
    name: "callFuncs",
    properties: {
        callback: null,
        target: null,
        once: false,
    }
})
//全局事件（事件名和事件回调事件回调数组，因为同一个事件可能有多个节点在监听，所以事件回调数组存放所有需要调用的函数以及调用函数的对象）
var globalEvent = cc.Class({
    name: "globalEvent",
    properties: {
        eventName: "",
        callbacks: {
            default: [],
            type: callFuncs,
        },
    },
    
})

var eventOrder = new cc.Enum({TOP_TO_BOTTOM: 0, BOTTOM_TO_TOP: 1})

cc.Class({
    extends: cc.Component,

    properties: {
        _eventList: {
            default : [],
            type: globalEvent
        },
        sendOrder: {
            default: eventOrder.TOP_TO_BOTTOM,
            type: eventOrder
        },
        _sendList: [],
        _removeList: [],
        _isStart: false
    },

    // use this for initialization
    onLoad: function () {
        //把GlobalEvent属性添加到director
        cc.director.GlobalEvent = this;
    },
    //所有在onLoad里添加的监听器，统一在start阶段进行派送，这样做的原因是，假设监听事件和派送事件都在onLoad进行，有可能派送事件比监听事件先发生，此次事件派送就会失效
    start: function () {
        this._isStart = true;
        for(let i = 0; i < this._sendList.length; i++){
            var event = this._sendList[i];
            this.sendEvent(event.eventName, event.data);
        }
        //start阶段派送完所有事件后，删除临时的事件列表
        this._sendList.splice(0, this._sendList.length);
        this._sendList.length > 0 ? this._sendList = [] : null;
    },
    //添加监听器（事件名，回调函数，目标对象，是否是一次性的事件）
    _monitor: function (eventName, callback, target, once) {
        //新建一个事件回调对象保存回调函数和目标对象
        var call = new callFuncs();
        //回调函数是否是函数对象
        callback instanceof Function ? call.callback = callback : cc.error("event callback not a function");
        //目标对象存不存在
        target ? call.target = target : cc.error("global event is not have target");
        //是否是一次性事件
        call.once = once;
        
        //如果事件列表不为空，则查找是否  已有  和  将要添加的事件    相同事件名的事件
        if(this._eventList.length > 0){
            //遍历事件列表
            for(let i = 0; i < this._eventList.length; i++){
                //如果已有相同事件
                if(this._eventList[i].eventName === eventName){
                    //则只增加事件回调
                    this._eventList[i].callbacks.push(call);
                    //不再查找
                    return ;
                //如果没有找到相同的事件
                }else if(i === this._eventList.length - 1){
                    //新建全局事件
                    var event = new globalEvent();
                    //事件名是否存在
                    eventName ? event.eventName = eventName : cc.error("event name is null");
                    //把创建好的事件回调添加到此次事件
                    event.callbacks.push(call);
                    //把此次事件添加到事件列表
                    this._eventList.push(event);
                    return ;
                }
            }
        //如果事件列表为空，则添加一个全局事件    
        }else{
            var event = new globalEvent();
            eventName ? event.eventName = eventName : cc.error("event name is null");
            event.callbacks.push(call);
            this._eventList.push(event);
        }
        
    },
    //发送事件
    sendEvent: function (eventName, data) {
        //如果还在onLoad阶段，保存要发送的事件，直接退出，在start阶段才开始发送事件
        if(!this._isStart){
            this._sendList.push({eventName: eventName, data: data});
            return ;
        }
        //cc.log("send event name is " + eventName);
        //遍历事件列表
        for(let i = 0; i < this._eventList.length; i++){
            //如果事件列表里有此次事件（任意一个对象添加了监听器，都会把事件存放在事件列表）
            if(this._eventList[i].eventName === eventName){
                //根据自定义的层级顺序发送事件
                if(this.sendOrder === eventOrder.BOTTOM_TO_TOP){
                    //遍历 事件 的 回调
                    for(let j = this._eventList[i].callbacks.length - 1; j >= 0; j--){
                        //目标对象
                        let target = this._eventList[i].callbacks[j].target;
                        //回调函数
                        let callback = this._eventList[i].callbacks[j].callback;
                        //是否继续传递此次事件
                        var goOn = true;
                        //停止传递此次事件
                        function stop() {
                            goOn = false;
                        };
                        //事件回调的参数（自定义的数据，停止传递事件的函数）
                        let event = {
                                    data: data, 
                                    stopSend: stop
                                    };
                        //调用回调函数
                        callback.call(target, event);

                        //如果停止了事件的传递
                        if(!goOn){
                            //不再触发 事件回调
                            break;
                        }
                        //如果删除了当前事件回调，则不执行后面的操作，而继续循环
                        if(!this._eventList[i].callbacks[j]){
                            continue ;
                        }
                        //如果当前的 事件回调 是一次性的，回调完成就删除当前这个 事件回调
                        if(this._eventList[i].callbacks[j].once){
                            this._eventList[i].callbacks.splice(j, 1);
                            //因为这里的顺序是从后到前，所以不管当前事件回调有没有被删除，j继续指向前一个事件回调
                        }

                    }
                }else if(this.sendOrder === eventOrder.TOP_TO_BOTTOM){
                    for(let j = 0; j < this._eventList[i].callbacks.length; j++){
                        let callback = this._eventList[i].callbacks[j].callback;
                        let target = this._eventList[i].callbacks[j].target;
                        var goOn = true;
                        function stop() {
                            goOn = false;
                        };
                        let event = {
                                    data: data, 
                                    stopSend: stop
                                    };
                        callback.call(target, event);

                        if(!goOn){
                            break;
                        }

                        if(!this._eventList[i].callbacks[j]){
                            j -=1;
                            continue ;
                        }
                        if(this._eventList[i].callbacks[j].once){
                            this._eventList[i].callbacks.splice(j, 1);
                            //这里的顺序是从前到后，如果删除一个元素后，后面每个元素的下标都会-1；
                            j -=1;
                        }

                    }
                }
                
                //找到事件并触发完成后，不再继续查找 
                return;
            }
        }
    },
    //添加一次性事件
    addMonitorOnce: function (eventName, callback, target) {
        this._monitor(eventName, callback, target, true);
    },
    //添加普通事件
    addMonitor: function (eventName, callback, target) {
        this._monitor(eventName, callback, target, false);
    },
    //通过事件名和target移除一个监听器
    removeMonitor: function (eventName, target) {
        for(let i = 0; i < this._eventList.length; i++){
            //找到事件
            if(this._eventList[i].eventName === eventName){
                for(let j = 0; j < this._eventList[i].callbacks.length; j++){
                    //找到事件回调
                    if(this._eventList[i].callbacks[j].target === target){
                        //移除回调对象上的监听器
                        this._eventList[i].callbacks.splice(j, 1);
                    }
                }
                
            }
        }
    },
    //移除所有事件监听
    removeAllMonitor: function () {
        this._eventList.splice(0, this._eventList.length);
        this._eventList.length > 0 ? this._eventList = [] : null;
    },

    // called every frame, uncomment this function to activate update callback
    // update: function (dt) {

    // },
});
